/**
 * 有时你确实想直接调用构造函数。在一个已存在的对象上调用构造函数是没有意义的，由于构造函数用来初始化对象。
 * 而一个对象只能在给它初值时被初始化一次。
 * 可是有时你有一些已经被分配可是尚未处理的的(raw)内存，你须要在这些内存中构造一个对象。你能够使用一个特殊的operator new ，它被称为placement new。
 * 
 * 注意： placement new 的 delete 是给异常处理用的。如果不写，只是放弃处理 ctor 发出的异常
*/

#include <cstdlib>
#include <cstring>

#include <iostream>

using namespace std;

class Bad : public exception
{
  public:
    const char *what() const throw()
    {
        return "Error Bad!\n";
    }
};

class Foo
{
  public:
    Foo() { cout << "Foo::Foo()" << endl; }
    Foo(int)
    {
        cout << "Foo::Foo(int)" << endl;
        throw Bad();
    }

    void *operator new(size_t size)
    {
        cout << __FUNCTION__ << "(size_t size)"
             << " size=" << size << endl;

        return malloc(size);
    }

    void *operator new(size_t size, void *start)
    {
        cout << __FUNCTION__ << "(size_t size, void *start)"
             << " size=" << size << " start=" << start << endl;

        return start;
    }

    void *operator new(size_t size, long extra)
    {
        cout << __FUNCTION__ << "(size_t size, long extra)"
             << " size=" << size << " extra=" << extra << endl;

        return malloc(size + extra);
    }

    void *operator new(size_t size, long extra, char init)
    {
        cout << __FUNCTION__ << "(size_t size, long extra, char init)"
             << " size=" << size << " extra=" << extra << " init=" << init << endl;

        return malloc(size + extra);
    }

    void operator delete(void *)
    {
        cout << __FUNCTION__ << "(void *)" << endl;
    }

    void operator delete(void *, void *)
    {
        cout << __FUNCTION__ << "(void *, void *)" << endl;
    }

    void operator delete(void *, long)
    {
        cout << __FUNCTION__ << "(void *, long)" << endl;
    }

    void operator delete(void *, long, char)
    {
        cout << __FUNCTION__ << "(void *, long, char)" << endl;
    }
};

int main()
{

    Foo *p1 = new Foo;
    delete p1;

    Foo start;
    cout << "start address=" << &start << endl;
    Foo *p2 = new (&start) Foo;
    delete p2;

    Foo *p3 = new (100) Foo;
    delete p3;

    Foo *p4 = new (100, 'a') Foo;
    delete p4;

    try
    {
      //  Foo *p5 = new (100) Foo(1);

       // Foo *p6 = new (100, 'a') Foo(1);
       // Foo *p7 = new (&start) Foo(1);
        Foo *p8 = new Foo(1);
    }
    catch (Bad &me)
    {
        cout << me.what();
    }
}